package com.ffs.lock;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.TreeSet;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 锁工具类
 *
 * @author ffs80 created 2021/7/2
 */
public class LockUtils {

    private static ObjectLockHolder holder = new ObjectLockHolder();

    /**
     * 数组参数
     */
    public static ChainLock getLock(Object... objects) {
        List<ObjectLock> locks = loadLocks(objects);
        return new ChainLock(locks);
    }

    /**
     * 列表参数
     */
    public static ChainLock getLock(List<Object> objects) {
        List<ObjectLock> locks = loadLocks(objects.toArray());
        return new ChainLock(locks);
    }


    private static List<ObjectLock> loadLocks(Object[] arrayOfObject) {
        List<ObjectLock> locks = new ArrayList<>();
        for (int i = 0; i < arrayOfObject.length; i++) {
            Object obj = arrayOfObject[i];
            ObjectLock lock = holder.getLock(obj);
            if ((lock != null) && (!locks.contains(lock))) {
                locks.add(lock);
            }
        }

        Collections.sort(locks);

        TreeSet<Integer> idx = new TreeSet<>();
        ObjectLock lock1, lock2;

        for (int i = 1; i < locks.size(); i++) {
            lock1 = locks.get(i - 1);
            lock2 = locks.get(i);
            if (lock1.isTie(lock2)) {
                idx.add(i);
            }
        }
        if (idx.isEmpty()) {
            return locks;
        }

        List<ObjectLock> newLocks = new ArrayList<>(locks.size() + idx.size());
        newLocks.addAll(locks);
        for (Integer i : idx) {
            ObjectLock lock = locks.get(i);
            ReentrantLock tieLock = holder.getTieLock(lock.getClazz());
            newLocks.add((ObjectLock) tieLock);
        }


        return newLocks;
    }
}
